﻿// Inner Fire 游戏引擎库
// 帧资源类
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 这个类用于进行帧资源的操作。使CPU与GPU不需要等待同步进行操作。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-19

#pragma once

#include <dx/core/dx_core.h>
#include <dx/core/dx_utils.h>
#include <dx/core/frame_resource_buffers.h>
#include <dx/core/upload_buffer.h>
#include <dx/ui/ui_instanced_data.h>
#include <dx/view/light.h>
#include <graphics/frame_resources_def.h>

namespace ifire::dx {

constexpr int MAX_LIGHTS = 16;

struct PassConstants {
  DirectX::XMFLOAT4X4 View = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 InvView = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 Proj = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 InvProj = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 ViewProj = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 InvViewProj = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 ViewProjTex = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 ShadowTransform = IDENTITY_4X4;
  DirectX::XMFLOAT3 EyePosW = {0.0f, 0.0f, 0.0f};
  float per_object_pad1 = 0.0f;
  DirectX::XMFLOAT2 RenderTargetSize = {0.0f, 0.0f};
  DirectX::XMFLOAT2 InvRenderTargetSize = {0.0f, 0.0f};
  float NearZ = 0.0f;
  float FarZ = 0.0f;
  float TotalTime = 0.0f;
  float DeltaTime = 0.0f;
  DirectX::XMFLOAT4 AmbientLight = {0.0f, 0.0f, 0.0f, 1.0f};
  DirectX::XMFLOAT4 FogColor = {0.7f, 0.7f, 1.0f, 1.0f};
  float gFogStart = 5.0f;
  float gFogRange = 300.0f;
  DirectX::XMFLOAT2 cbPerObjectPad2;
  Light lights[MAX_LIGHTS];
};

constexpr auto PASS_CB_SIZE = calc_constant_buffer_size(sizeof(PassConstants));

class FrameResource {
public:
  FrameResource(ID3D12Device* device, const FrameResourceDesc& desc);
  FrameResource(const FrameResource& lhs) = delete;
  FrameResource& operator=(const FrameResource& lhs) = delete;
  ~FrameResource() = default;

  // 得到MainPass的索引
  int MainPassIndex() { return 0; }
  // 获得ShadowPass的索引，注意这里会有BUG，因为不会自动计算，等以后填充
  int ShadowPassIndex() { return 1; }

  // 在GPU处理完与此命令分配器相关的命令之前，我们不能对它进行重置。
  // 所以每一帧都需要有自已的命令分配器。
  ComPtr<ID3D12CommandAllocator> allocator;

  // 项目的描述符，用于获取一些信息
  FrameResourceDesc desc;

  // 在GPU执行完此常量缓冲区的命令之前，我们不能对它进行更新
  // 所以每一帧要有它们自已的常量缓冲区
  UploadBufferPtr<PassConstants> pass_cb = nullptr;
  UploadBufferPtr<ObjectConstants> object_cb = nullptr;
  UploadBufferPtr<MaterialData> material_buffer = nullptr;
  UploadBufferPtr<SsaoConstants> ssao_cb = nullptr;
  UploadBufferPtr<UIInstancedData> ui_cb = nullptr;
  UploadBufferPtr<UIInstancedData> text_cb = nullptr;
  UploadBufferPtr<SkinnedConstants> skinned_cb = nullptr;

  // 用于实例化精灵
  UploadBufferPtr<InstancedSpriteConstants> instanced_sprite_cb = nullptr;
  // 用于地图
  UploadBufferPtr<InstancedSpriteConstants> map_block_cb = nullptr;

  // 用于管理实例化精灵
  FrameResourceBuffers<InstancedSpriteData> instanced_sprite;

  // 通过围栏值将命令标记到此围栏点，使我们可以检查到GPU是否还在使用此帧资源
  UINT64 Fence = 0;
};

} // namespace ifire::dx